package de.wtschreiter.structured.document.io.event;

import static org.junit.Assert.*;

import org.junit.Test;

public class EventBuilderTest {

    @Test
    public void buildCharacterDataEvent() throws Exception {
        final CharSequence data = "Some CharacterData";
        final CharacterDataEvent characterDataEvent = buildBinaryDataEvent(new EventBuilder(), data);
        assertEquals(data, characterDataEvent.getData());
    }

    private CharacterDataEvent buildBinaryDataEvent(final EventBuilder eventBuilder, final CharSequence data) {
        final CharacterDataEvent characterDataEvent = eventBuilder.appendCharacterData(data).createCharacterDataEvent();
        assertNotNull(characterDataEvent);
        return characterDataEvent;
    }

    @Test
    public void buildBinaryDataEvent() throws Exception {
        final byte[] data = new byte[] { 0x00, 0x01, 0x02, 0x03 };
        final BinaryDataEvent binaryDataEvent = buildBinaryDataEvent(new EventBuilder(), data);
        assertEventType(binaryDataEvent, EventType.BINARY_DATA);
        assertArrayEquals(data, binaryDataEvent.getData());
    }

    private BinaryDataEvent buildBinaryDataEvent(final EventBuilder eventBuilder, final byte[] data) {
        final BinaryDataEvent binaryDataEvent = eventBuilder.appendBinaryData(data).createBinaryDataEvent();
        assertNotNull(binaryDataEvent);
        return binaryDataEvent;
    }

    @Test
    public void buildEndElementEvent() throws Exception {
        final EndElementEvent endDocumentEvent = buildEndElementEvent(new EventBuilder());
        assertEventType(endDocumentEvent, EventType.END_ELEMENT);
    }

    private EndElementEvent buildEndElementEvent(final EventBuilder eventBuilder) {
        final EndElementEvent endElementEvent = eventBuilder.createEndElementEvent();
        assertNotNull(endElementEvent);
        return endElementEvent;
    }

    @Test
    public void buildStartElementEventWithoutAttributes() throws Exception {
        final StartElementEvent startElementEvent = buildStartElement(new EventBuilder());
        assertEventType(startElementEvent, EventType.START_ELEMENT);
        assertAttributes(startElementEvent, new Attribute("a-attribute-key", EventConstance.EMPTY_ATTRIBUTE_VALUE));
    }

    @Test
    public void buildStartElementEventWithAttributes() throws Exception {
        final Attribute attribute = new Attribute("a-attribute-key", "a-attribute-value");
        EventBuilder eventBuilder = new EventBuilder();
        eventBuilder = appendAttributeToEventBuilder(eventBuilder, attribute);
        final StartElementEvent startElementEvent = buildStartElement(eventBuilder);
        assertEventType(startElementEvent, EventType.START_ELEMENT);
        assertAttributes(startElementEvent, attribute);
    }

    private StartElementEvent buildStartElement(final EventBuilder eventBuilder) {
        final StartElementEvent result = eventBuilder.createStartElementEvent();
        assertNotNull(result);
        return result;
    }

    @Test
    public void buildEndDocument() throws Exception {
        final EndDocumentEvent endDocumentEvent = buildEndDocumentEvent();
        assertEventType(endDocumentEvent, EventType.END_DOCUMENT);
    }

    private EndDocumentEvent buildEndDocumentEvent() {
        final EndDocumentEvent endDocumentEvent = new EventBuilder().createEndDocumentEvent();
        assertNotNull(endDocumentEvent);
        return endDocumentEvent;
    }

    @Test
    public void buildStartDocumentWithAttributes() throws Exception {
        final Attribute attribute = new Attribute("a-attribute-key", "a-attribute-value");
        EventBuilder eventBuilder = new EventBuilder();
        eventBuilder = appendAttributeToEventBuilder(eventBuilder, attribute);
        final StartDocumentEvent startDocumentEvent = buildStartDocument(eventBuilder);
        assertEventType(startDocumentEvent, EventType.START_DOCUMENT);
        assertAttributes(startDocumentEvent, attribute);
    }

    @Test
    public void buildStartDocumentWithoutAttributes() throws Exception {
        final Attribute attribute = new Attribute("a-attribute-key", EventConstance.EMPTY_ATTRIBUTE_VALUE);
        final EventBuilder eventBuilder = new EventBuilder();
        final StartDocumentEvent startDocumentEvent = buildStartDocument(eventBuilder);
        assertAttributes(startDocumentEvent, attribute);
    }

    private void assertEventType(final Event event, final EventType eventType) {
        assertEquals(eventType, event.getType());
    }

    private void assertAttributes(final AttributedEvent event, final Attribute... attributes) {
        for (final Attribute attribute : attributes) {
            assertEquals(attribute.value, event.getAttribute(attribute.key));
        }
    }

    private StartDocumentEvent buildStartDocument(final EventBuilder eventBuilder) {
        final StartDocumentEvent startDocumentEvent = eventBuilder.createStartDocumentEvent();
        assertNotNull(startDocumentEvent);
        return startDocumentEvent;
    }

    private EventBuilder appendAttributeToEventBuilder(EventBuilder eventBuilder, final Attribute attribute) {
        eventBuilder = eventBuilder.appendAttribute(attribute.key, attribute.value);
        assertNotNull(eventBuilder);
        return eventBuilder;
    }

    private static class Attribute {
        private final String key;
        private final String value;

        public Attribute(final String key, final String value) {
            this.key = key;
            this.value = value;
        }
    }

}
